#include <sys/syscall.h>
#include <mips/regdef.h>

        .text
        .align  2
#define CTL_FRAME_SIZE 16 
#define CTL_GP 8 
#define CTL_FP 12 
#define CTL_CHAR 0

        .globl  char_to_low2
        .ent    char_to_low2
char_to_low2:
        .frame  $fp,CTL_FRAME_SIZE,ra 
        .set    noreorder
        .cpload t9
        .set    reorder
        subu    sp,sp,CTL_FRAME_SIZE
        .cprestore 0

        sw      $fp,CTL_FP(sp)
        sw      gp,CTL_GP(sp)
        move    $fp,sp

        move    t0,a0                           # Guardo caracter recibido por parametro en t0
        sb      t0,CTL_CHAR($fp)
        lbu     t1,CTL_CHAR($fp)
        sltu    t1,t1,65                        # Si c es menor a 'A' pongo 1 en t1, sino pongo 0.
        bne     t1,zero,es_min                  # Salto si es distinto a cero (c es minuscula).
        lbu     t1,CTL_CHAR($fp)
        sltu    t1,t1,91                        # Si c es menor a 'Z' pongo 1 en t1, sino pongo 0.
        beq     t1,zero,es_min                  # Salto si es igual a cero (c es minuscula).
        lbu     t1,CTL_CHAR($fp)
        addu    t1,t1,32                        # Sumo 32 al caracter para convertirlo a minuscula.
		move	v0,t1
        b       fin_CTL
es_min:
        lbu     v0,CTL_CHAR($fp)
fin_CTL:
        move    sp,$fp
        lw      $fp,CTL_FP(sp)
        lw      gp,CTL_GP(sp)
        addu    sp,sp,CTL_FRAME_SIZE
        j       ra
        .end    char_to_low2
        .size   char_to_low2, .-char_to_low2


        .align  2
#define C_FRAME_SIZE 	48   
#define C_RA 		40    
#define C_FP 		36   
#define C_GP 		32   
#define C_I		20   
#define C_AUXA		24   
#define C_AUXB		25  
#define C_PARAM0	48
#define C_PARAM1	52  
        .globl  comparar2
        .ent    comparar2
comparar2:
        .frame  $fp,C_FRAME_SIZE,ra             # vars= 16, regs= 3/0, args= 16, extra= 8
        .set    noreorder
        .cpload t9
        .set    reorder
        subu    sp,sp,C_FRAME_SIZE
        .cprestore 16
        sw      ra,C_RA(sp)
        sw      $fp,C_FP(sp)
        sw      gp,C_GP(sp)
        move    $fp,sp
        sw      a0,C_PARAM0($fp)	# parametro 0
        sw      a1,C_PARAM1($fp)	# parametro 1
        sw      zero,C_I($fp)		# int i=0
while:
        lw      t1,C_PARAM0($fp)	# cargo direccion del primer parametro "char* a"
        lw      t0,C_I($fp)		# cargo variable "i" 
        addu    t0,t1,t0		# cargo posicion i dentro de la palabra
        lbu     t0,0(t0)		# me quedo solo con el caracter que necesito comparar
		beq     t0,$0,comp_chars		# si el caracter es 0 termino la palabra
        lw      t1,C_PARAM1($fp)	# cargo direccion del 2do parametro "char* b"
        lw      t2,C_I($fp)		# cargo variable "i"
        addu    t2,t1,t2		# cargo posicion i dentro de la palabra
        lbu     t2,0(t2)		# me quedo solo con el caracter que necesito comparar
        bne     t2,zero,comparo		# si el caracter de la 2da palabra no es 0 sigue el while
        b       comp_chars		# finaliza el while porque la 2da palabra tiene un 0
comparo:
        lw      t1,C_PARAM0($fp)
        lw      t0,C_I($fp)
        addu    t0,t1,t0
        lbu     t0,0(t0)
        move    a0,t0
        la      t9,char_to_low2		# combierto el caracter a[i] a minuscula
        jal     ra,t9
        sb      v0,C_AUXA($fp)		# guardo resultado en C_AUXA
        
		lw      t1,C_PARAM1($fp)
        lw      t0,C_I($fp)
        addu    t0,t1,t0
        lbu     t0,0(t0)
        move    a0,t0
		la      t9,char_to_low2		# combierto el caracter b[i] a minuscula
        jal     ra,t9
        sb      v0,C_AUXB($fp)		#guardo resultado en C_AUXB
        
		lb      t1,C_AUXA($fp)
        lb      t0,C_AUXB($fp)
        beq     t1,t0,INC_I		# si C_AUXA==CAUXB incremento "i" y vuelvo al while
        
		lb      t0,C_AUXA($fp)		
        lb      t1,C_AUXB($fp)
        subu    v0,t0,t1		# guardo resultado en v0 para terminar
        b       fin_comp
INC_I:
        lw      t0,C_I($fp)
        addu    t0,t0,1
        sw      t0,C_I($fp)
        b       while
comp_chars:
		lw      t1,C_PARAM0($fp)
        lw      t0,C_I($fp)
        addu    t0,t1,t0
        lbu     t0,0(t0)
        move    a0,t0
        la      t9,char_to_low2
        jal     ra,t9
        sb      t0,C_AUXA($fp)
        lw      t1,C_PARAM1($fp)
        lw      t0,C_I($fp)
        addu    t0,t1,t0
        lbu     t0,0(t0)
        move    a0,t0
        la      t9,char_to_low2
        jal     ra,t9
        sb      t0,C_AUXB($fp)
        lb      t0,C_AUXA($fp)
        lb      t0,C_AUXB($fp)
        subu    v0,v0,v1
fin_comp:
        move    sp,$fp
        lw      ra,C_RA(sp)
        lw      $fp,C_FP(sp)
        addu    sp,sp,C_FRAME_SIZE
        j       ra
        .end    comparar2
        .size   comparar2, .-comparar2 


		.align	2
#define S_FRAME_SIZE 64
#define S_WORDS 64
#define S_ARRAYSIZE 68
#define S_RA 56
#define S_FP 52
#define S_GP 48
#define S_VAR_Pdiv2 40
#define S_VAR_P 24
#define S_VAR_I 28
#define S_VAR_TMP 36
#define S_VAR_J 32

		.globl	shellsort
		.ent	shellsort
shellsort:
		.frame	$fp,S_FRAME_SIZE,ra
		.mask	0xd0000000,-8
		.fmask	0x00000000,0
		.set	noreorder
		.cpload	t9
		.set	reorder
		subu	sp,sp,S_FRAME_SIZE
		.cprestore 16
#---------------------------
		sw	ra,S_RA(sp)	# guardo ra
		sw	$fp,S_FP(sp)	# guardo fp
		sw	gp,S_GP(sp)	# guardo gp
		move	$fp,sp
		sw	a0,S_WORDS($fp)	# guardo arg0 (char **words)
		sw	a1,S_ARRAYSIZE($fp)	# guardo arg1 (int arraysize)
#---------------------------
		lw	t1,S_ARRAYSIZE($fp)	# cargo arg1 (arraysize)
		sra	t1,t1,31	# divido por 2
		srl	t1,t1,31
		addu	t2,t0,t1
		sra	t2,t2,1
		sw	t2,S_VAR_P($fp)	# guardo p = arraysize / 2
for_1:
		lw	t0,S_VAR_P($fp)	# leo p
		sw	t0,S_VAR_I($fp)	# inicializo i con valor p. (i = p)
for_2:
		lw	t0,S_VAR_I($fp)	# leo i
		sll	t1,t0,2		# multiplico i * 4, (i * sizeof(int))
		lw	t0,S_WORDS($fp)	# leo arg0 (words)
		addu	t0,t1,t0	# sumo la cantidad de bytes al puntero words para incrementarlo (words[i])
		lw	t0,0(t0)	# leo el valor al que apunta words[i]
		sw	t0,S_VAR_TMP($fp)	# inicializo tmp. (tmp = words[i])
		lw	t0,S_VAR_I($fp)	# leo i
		sw	t0,S_VAR_J($fp)	# guardo i en j. (j = i)
for_3:
		lw	t0,S_VAR_J($fp)	# leo j
		lw	t1,S_VAR_P($fp)	# leo p
		slt	t0,t0,t1	# (j < p) ?
		bne	t0,zero,end_loop_3	# si se cumple el if => branch
		lw	t1,S_VAR_J($fp)	# leo j
		lw	t0,S_VAR_P($fp)	# leo p
		subu	t0,t1,t0	# (j - p)  (para el indice)
		sll	t1,t0,2		# multiplico por 4 (para tener la cantidad de bytes)
		lw	t0,S_WORDS($fp)	# leo words
		addu	t0,t1,t0	# incremento words
		lw	a0,S_VAR_TMP($fp)	# pongo 1er argumento
		lw	a1,0(t0)	# pongo 2do argumento
		la	t9,comparar2	# cargo la direccion de comparar
		jal	ra,t9		# invoco la funcion comparar
		bgez	v0,end_loop_3	# si se cumple el if => branch
		lw	t0,S_VAR_J($fp)	# leo j
		sll	t1,t0,2		# multiplico para tener la cantidad de bytes
		lw	t0,S_WORDS($fp)	# leo words
		addu	a0,t1,t0	# incremento el puntero words
		lw	t1,S_VAR_J($fp)	# leo j
		lw	t0,S_VAR_P($fp)	# leo p
		subu	t0,t1,t0	# j - p
		sll	t1,t0,2		# multiplico por 4 para tener los bytes
		lw	t0,S_WORDS($fp)	# leo words
		addu	t0,t1,t0	# incremento el puntero words
		lw	t0,0(t0)	# leo words[j - p]
		sw	t0,0(a0)	# guardo en words[j]
		lw	t1,S_VAR_J($fp)	# leo j
		lw	t0,S_VAR_P($fp)	# leo p
		subu	t0,t1,t0	# (j - p)
		sw	t0,S_VAR_J($fp)	# j = (j - p)
		b	for_3
end_loop_3:
		lw	t0,S_VAR_J($fp)	# leo j
		sll	t1,t0,2
		lw	t0,S_WORDS($fp)	 # leo words
		addu	t1,t1,t0
		lw	t0,S_VAR_TMP($fp)
		sw	t0,0(t1)	# words[j] = tmp
		lw	t0,S_VAR_I($fp)
		addu	t0,t0,1		# i++
		sw	t0,S_VAR_I($fp)
		lw	t1,S_VAR_I($fp)
		lw	t0,S_ARRAYSIZE($fp)
		slt	t0,t1,t0
		beq	t0,zero,false_comp	# branch si !(i < arraySize)
		b	for_2
false_comp:
		lw	t1,S_VAR_P($fp)
		li	t0,2
		beq	t1,t0,p_eq_1	# branch si (p == 2)
		lw	t1,S_VAR_P($fp)
		sra	t0,t1,31	# divido p por 2
		srl	t0,t0,31
		addu	t0,t1,t0
		sra	t0,t0,1
		sw	t0,S_VAR_Pdiv2($fp) # p = (p / 2)
		b	S_continue
p_eq_1:
		li	t0,1
		sw	t0,S_VAR_Pdiv2($fp)
S_continue:
		lw	t0,S_VAR_Pdiv2($fp)
		sw	t0,S_VAR_P($fp)
		lw	t0,S_VAR_P($fp)
		blez	t0,S_end
		b	for_1
S_end:
		move	sp,$fp
		lw	ra,S_RA(sp)
		lw	$fp,S_FP(sp)
		addu	sp,sp,S_FRAME_SIZE
		j	ra
		.end	shellsort
		.size	shellsort, .-shellsort
		.ident	"GCC: (GNU) 3.3.3 (NetBSD nb3 20040520)"
